{% extends "base.html" %}

{% block title %}地图定位数据展示{% endblock %}
{% block page_title %}地图定位数据展示{% endblock %}

{% block content %}
    <style>
        /* 整体控制面板容器 */
        #map-controls-container {
            display: grid;
            grid-template-columns: 2fr 1fr; /* 默认两列布局 */
            gap: 20px;
            margin-bottom: 20px;
        }

        /* 单个控制卡片样式 */
        .control-card {
            background-color: #fcfcfc;
            border: 1px solid var(--border-color);
            padding: 20px;
            border-radius: 8px;
            box-shadow: 0 2px 5px rgba(0,0,0,0.05);
        }

        /* 响应式布局：小屏幕单列 */
        @media (max-width: 991px) {
            #map-controls-container {
                grid-template-columns: 1fr; /* 小屏幕下改为单列 */
            }
        }
        
        /* 针对常规查询卡片内部布局 */
        #static-query-card {
            display: grid;
            grid-template-columns: repeat(auto-fit, minmax(250px, 1fr)); /* 响应式布局 */
            gap: 20px;
            align-items: flex-end;
        }

        #static-query-card label {
            display: block;
            margin-bottom: 8px;
            font-weight: 500;
            color: var(--heading-color);
            font-size: 0.95em;
        }
        #static-query-card select,
        #static-query-card input[type="text"],
        #static-query-card input[type="number"] {
            width: 100%;
            padding: 10px 12px;
            border: 1px solid #ccc;
            border-radius: 5px;
            font-size: 1em;
            box-sizing: border-box;
            background-color: white;
            transition: border-color 0.2s ease, box-shadow 0.2s ease, background-color 0.2s ease;
        }
        #static-query-card select:focus,
        #static-query-card input[type="text"]:focus,
        #static-query-card input[type="number"]:focus {
            border-color: var(--primary-color);
            box-shadow: 0 0 0 3px rgba(52, 152, 219, 0.2);
            outline: none;
        }
        /* 禁用时的样式 */
        #static-query-card select:disabled,
        #static-query-card input[type="text"]:disabled,
        #static-query-card input[type="number"]:disabled {
            background-color: #e9ecef;
            cursor: not-allowed;
            opacity: 0.7; /* 稍微透明 */
        }
        /* ID选择器选中项的样式 */
        #idSelector option:checked {
            background-color: #e0f2f7; /* 淡蓝色，更美观 */
            color: #333;
            font-weight: 600;
        }

        #static-query-card .input-group {
            display: flex;
            gap: 10px;
        }
        #static-query-card .radio-group {
            display: flex;
            gap: 20px;
            margin-top: 10px;
            align-items: center;
        }
        #static-query-card .radio-group label {
            display: flex;
            align-items: center;
            margin-bottom: 0;
            font-weight: normal;
        }
        #static-query-card .radio-group input[type="radio"] {
            margin-right: 5px;
            width: auto;
        }
        /* 禁用Radio按钮的文本颜色 */
        #static-query-card .radio-group input[type="radio"]:disabled + label {
            color: #999;
            cursor: not-allowed;
        }

        #static-query-card .button-wrapper {
            grid-column: span 1; /* 占据一列 */
            display: flex;
            justify-content: flex-end; /* 按钮靠右对齐 */
            align-items: flex-end; /* 底部对齐 */
        }
        .button { /* 沿用 base.html 的 button 样式 */
            display: inline-block;
            padding: 10px 20px;
            background-color: var(--primary-color);
            color: white;
            text-decoration: none;
            border-radius: 6px;
            transition: background-color 0.2s ease, transform 0.1s ease;
            font-size: 1em;
            font-weight: 600;
            border: none;
            cursor: pointer;
        }
        .button:hover {
            background-color: var(--primary-hover-color);
            transform: translateY(-1px);
        }
        .button.secondary {
            background-color: var(--secondary-color);
        }
        .button.secondary:hover {
            background-color: var(--secondary-hover-color);
        }
        .button:disabled {
            background-color: #ccc;
            cursor: not-allowed;
            transform: none;
            opacity: 0.7;
        }
        .small-button {
            padding: 8px 12px;
            font-size: 0.85em;
            font-weight: 500;
        }
        #id-selector-group { /* 用于包装ID选择器和全选按钮 */
            display: flex;
            flex-direction: column;
            gap: 10px; /* 间距 */
        }
        #select-all-ids-button {
            display: inline-block;
            padding: 8px 15px;
            background-color: var(--secondary-color);
            color: white;
            text-decoration: none;
            border-radius: 6px;
            transition: background-color 0.2s ease, transform 0.1s ease;
            font-size: 0.9em;
            font-weight: 500;
            border: none;
            cursor: pointer;
            align-self: flex-start; /* 按钮靠左 */
        }
        #select-all-ids-button:hover {
            background-color: var(--secondary-hover-color);
            transform: translateY(-1px);
        }
        #select-all-ids-button:disabled {
            background-color: #ccc;
            cursor: not-allowed;
            transform: none;
        }

        /* 新增：时间快速选择按钮组 */
        .time-range-controls {
            display: flex;
            flex-direction: column;
            gap: 10px;
        }
        .date-quick-select-buttons {
            display: flex;
            flex-wrap: wrap; /* 允许换行 */
            gap: 8px; /* 按钮之间间距 */
            margin-top: 5px; /* 与输入框的间距 */
        }


        /* ====== 实时更新控制卡片样式 ====== */
        #realtime-update-card {
            display: flex;
            flex-direction: column;
            gap: 15px;
        }
        #realtime-update-card h3 {
            margin-top: 0;
            color: var(--heading-color);
            font-size: 1.1em;
            border-bottom: 1px solid var(--border-color);
            padding-bottom: 10px;
        }

        .realtime-update-interval-group {
            display: flex;
            align-items: center;
            gap: 5px;
        }
        .realtime-update-interval-group label {
            font-weight: 500;
            color: var(--heading-color);
            margin-bottom: 0;
        }
        .realtime-update-interval-group input[type="number"] {
            width: 80px; /* 控制宽度 */
            text-align: center;
            padding: 8px 10px;
        }
        .realtime-update-info {
            font-size: 0.85em;
            color: #666;
        }
        #realtimeControlButton {
            width: 100%;
            padding: 12px 20px;
            background-color: var(--primary-color);
            color: white;
            border: none;
            border-radius: 6px;
            font-size: 1.05em;
            font-weight: 600;
            cursor: pointer;
            transition: background-color 0.2s ease, transform 0.1s ease;
            margin-top: 10px;
        }
        #realtimeControlButton:hover {
            background-color: var(--primary-hover-color);
            transform: translateY(-1px);
        }
        #realtimeControlButton:disabled {
            background-color: #ccc;
            cursor: not-allowed;
            transform: none;
        }
        /* ================================== */

        /* 消息提示框样式 */
        .map-status-message {
            text-align: center;
            padding: 20px;
            font-size: 1.1em;
            color: #7f8c8d;
            background-color: #f0f3f5;
            border-radius: 8px;
            margin-bottom: 20px;
            border: 1px dashed #c0c7cb;
        }
        .map-status-message.success {
            border: 1px dashed var(--success-color);
            color: var(--success-color);
            background-color: #e6f7ed;
        }
        .map-status-message.error {
            border: 1px dashed var(--error-color);
            color: var(--error-color);
            background-color: #fbe6e6;
        }
        .map-status-message.warning {
            border: 1px dashed var(--warning-color);
            color: var(--warning-color);
            background-color: #fff9e6;
        }


        /* 地图容器样式 */
        #container {
            position: relative; /* 为图例定位提供上下文 */
            width: 100%;
            height: 700px; /* 地图高度 */
            border-radius: 8px;
            box-shadow: 0 4px 15px rgba(0, 0, 0, 0.08);
            margin-top: 20px;
            border: 1px solid var(--border-color);
            overflow: hidden; /* 确保地图内容不溢出圆角 */
        }
        
        /* 信息窗体内容样式 */
        .amap-info-window-content {
            font-family: 'Noto Sans SC', sans-serif, Arial, sans-serif;
            font-size: 0.9em;
            line-height: 1.6;
            color: var(--text-color);
            padding: 5px; /* 确保内容有边距 */
        }
        .amap-info-window-content strong {
            color: var(--heading-color);
        }
        .amap-info-window-content .info-item {
            margin-bottom: 5px;
        }

        /* 针对小屏幕适配 */
        @media (max-width: 576px) {
            #container {
                height: 500px; /* 更小的屏幕更小的高度 */
            }
            #map-legend {
                left: 15px; /* 小屏幕上图例靠左显示，避免遮挡 */
                right: auto;
            }
        }

        /* ================== 自定义Marker和图例样式 ================== */

        /* 自定义蓝色小圆点标记样式（用于历史坐标点） */
        .blue-dot-marker {
            width: 8px; /* 小圆 */
            height: 8px;
            background-color: #007bff; /* 蓝色 */
            border-radius: 50%;
            border: 1px solid #fff;
            box-shadow: 0 0 2px rgba(0,0,0,0.5);
            margin: -4px 0 0 -4px; /* 使点居中 */
            box-sizing: border-box;
            cursor: pointer;
        }
        /* 选中蓝色圆点的特殊样式 - 改为红色高亮 */
        .blue-dot-marker.selected {
            border: 2px solid red; /* 选中时边框变红 */
            width: 12px; /* 稍大 */
            height: 12px;
            margin: -6px 0 0 -6px; /* 重新居中 */
            box-shadow: 0 0 5px red; /* 添加红色光晕 */
        }

        /* 自定义图标样式 (高德默认图标是 25x34) */
        .amap-icon img {
            width: 25px;
            height: 34px;
            border: none;
            cursor: pointer;
            /* 为图标添加过渡效果，使高亮更平滑 */
            transition: box-shadow 0.2s ease-in-out; 
        }
        /* 选中红色图钉的特殊样式 - 添加红色光晕 */
        /* 这个类会在JS中动态添加到amap-marker-content元素上 */
        .amap-marker-content.red-pin-selected .amap-icon img {
            box-shadow: 0 0 8px 3px rgba(255, 0, 0, 0.7); /* 红色光晕 */
        }

        /* 地图图例样式 */
        #map-legend {
            position: absolute;
            top: 15px;
            right: 15px;
            background-color: rgba(255, 255, 255, 0.9);
            padding: 10px 15px;
            border-radius: 8px;
            box-shadow: 0 2px 8px rgba(0, 0, 0, 0.15);
            z-index: 999;
            font-size: 0.9em;
            color: var(--text-color);
            transition: all 0.3s ease-in-out; /* 平滑过渡 */
        }
        #map-legend h4 {
            margin-top: 0;
            margin-bottom: 10px;
            font-size: 1.1em;
            color: var(--heading-color);
            border-bottom: 1px solid var(--border-color);
            padding-bottom: 5px;
        }
        #map-legend .legend-item {
            display: flex;
            align-items: center;
            margin-bottom: 8px;
        }
        /* 隐藏图例项的类 */
        .hidden-legend-item {
            display: none !important;
        }

        #map-legend .legend-color-box {
            width: 28px; /* 确保有足够空间显示图标或圆点 */
            height: 28px;
            border-radius: 4px;
            margin-right: 10px;
            border: 1px solid #ccc; /* 增加边框，更清晰 */
            background-color: #f9f9f9; /* 略微不同的背景色 */
            display: flex;
            justify-content: center;
            align-items: center;
            flex-shrink: 0; /* 防止内容收缩 */
        }
        #map-legend .legend-color-box img {
            max-width: 100%;
            max-height: 100%;
            object-fit: contain; /* 确保图标完整显示 */
            width: 25px; /* 图例中图标尺寸 */
            height: 34px;
            border: none;
        }
        #map-legend .legend-color-box .blue-dot-legend { /* 图例中用不同的类 */
            width: 10px; /* 稍大一点，适应图例盒 */
            height: 10px;
            background-color: #007bff; /* 蓝色 */
            border-radius: 50%;
            border: 1px solid #fff;
            box-shadow: 0 0 1px rgba(0,0,0,0.3);
        }
        #map-legend .legend-color-box .polyline-style-legend {
            height: 4px;
            width: 100%; /* 充满容器宽度 */
            background-color: #e77777; /* 轨迹线颜色示例 (灰色) */
            opacity: 0.6;
        }

    </style>

    <div id="map-controls-container">
        {# 常规数据查询卡片 #}
        <div id="static-query-card" class="control-card">
            <div id="id-selector-group">
                <label for="idSelector">选择ID</label>
                <select id="idSelector" multiple size="5"> {# multiple 属性允许多选，size 属性显示更多选项 #}
                    {% for id_option in display_id_options %} {# 使用 display_id_options #}
                        <option value="{{ id_option.original_id }}">{{ id_option.display_name }}</option>
                    {% endfor %}
                </select>
                <button id="select-all-ids-button" type="button" class="button secondary small-button">全选ID</button>
            </div>
            
            <div class="time-range-controls"> {# 包含时间范围输入框及新的快速选择按钮 #}
                <div class="time-range-group">
                    <label for="mapTimeRange">时间范围</label>
                    <input type="text" id="mapTimeRange" placeholder="选择时间范围"> {# 使用 Flatpickr 输入框 #}
                </div>
                <div class="date-quick-select-buttons">
                    <button id="todayBtnMap" type="button" class="button secondary small-button">今天</button>
                    <button id="lastMonthBtnMap" type="button" class="button secondary small-button">最近一月</button>
                    <button id="allTimeBtnMap" type="button" class="button secondary small-button">全部时间</button> {# 新增：全部时间按钮 #}
                </div>
            </div>

            <div> {# 包含显示模式 #}
                <div class="radio-group" style="margin-top: 10px;">
                    <label>
                        <input type="radio" name="displayMode" value="latest" checked> 最新位置
                    </label>
                    <label>
                        <input type="radio" name="displayMode" value="trajectory"> 轨迹
                    </label>
                </div>
            </div>

            <div class="button-wrapper">
                <button id="displayMapData" class="button">显示地图数据</button>
            </div>
        </div>
        
        {# 实时更新控制卡片 #}
        <div id="realtime-update-card" class="control-card">
            <h3>实时更新配置</h3>
            <div class="realtime-update-interval-group">
                <label for="refreshInterval">刷新间隔 (秒):</label>
                <input type="number" id="refreshInterval" value="10" min="1">
            </div>
            <p class="realtime-update-info" id="realtimeInfoText">实时更新将显示**当前已选择ID**的最新有效位置。</p>
            <button id="realtimeControlButton" class="button secondary">开始实时更新</button> {# 默认显示开始按钮 #}
        </div>
    </div>

    {# 两个消息提示区域 #}
    <div id="noMapDataMessage" class="map-status-message" style="display: none;">
        当前筛选条件下没有找到任何有效的定位数据。
    </div>
    <div id="realtimeStatusMessage" class="map-status-message success" style="display: none;">
        实时更新中... (每 <span id="currentRefreshInterval">10</span> 秒刷新一次)
    </div>

    <div id="container">
        <!-- 图例将在这里动态生成 -->
    </div>

    <script type="text/javascript">
        // ！！！重要：请将此处的 securityJsCode 替换为您自己的高德JS API 安全密钥！！！
        window._AMapSecurityConfig = {
            securityJsCode: '{{ amap_jsapi_key }}', // 使用后端传递的密钥
        };
    </script>
    <script type="text/javascript" src="https://webapi.amap.com/maps?v=2.0&key={{ amap_jsapi_key }}&plugin=AMap.MarkerClusterer,AMap.ToolBar,AMap.Scale,AMap.ControlBar"></script>
    <script type="text/javascript">
        console.log('--- Frontend Debugging Start: Script Loaded (map.html) ---');

        const allMessagesGroupedById = {{ all_messages_grouped_by_id | tojson }};
        const displayIdOptions = {{ display_id_options | tojson }}; // 使用 Flask 传递的包含 display_name 和 original_id 的列表
        
        // DOM 元素获取
        const idSelector = document.getElementById('idSelector');
        const selectAllIdsButton = document.getElementById('select-all-ids-button');
        const mapTimeRangeInput = document.getElementById('mapTimeRange'); // Flatpickr input
        const todayBtnMap = document.getElementById('todayBtnMap'); // 新增：今天按钮
        const lastMonthBtnMap = document.getElementById('lastMonthBtnMap'); // 新增：最近一月按钮
        const allTimeBtnMap = document.getElementById('allTimeBtnMap'); // 新增：全部时间按钮
        const displayModeRadios = document.querySelectorAll('input[name="displayMode"]');
        const displayModeLatestRadio = document.querySelector('input[name="displayMode"][value="latest"]');
        const displayModeTrajectoryRadio = document.querySelector('input[name="displayMode"][value="trajectory"]');
        const displayMapDataButton = document.getElementById('displayMapData'); // 非实时模式的显示数据按钮
        const mapContainer = document.getElementById('container');
        const noMapDataMessage = document.getElementById('noMapDataMessage');
        const realtimeStatusMessage = document.getElementById('realtimeStatusMessage');
        const currentRefreshIntervalSpan = document.getElementById('currentRefreshInterval');
        
        // 实时更新相关DOM元素和变量
        const refreshIntervalInput = document.getElementById('refreshInterval');
        const realtimeInfoText = document.getElementById('realtimeInfoText');
        const realtimeControlButton = document.getElementById('realtimeControlButton'); // 实时模式的控制按钮

        let realtimeUpdateIntervalId = null; // 用于存储实时更新的定时器ID
        const defaultRealtimeRefreshInterval = 10; // 默认刷新间隔秒数
        let latestRealtimeMarkers = {}; // 存储实时更新模式下地图上显示的最新标记，键是IdNumber

        let map = null;
        let markers = []; // 存储所有地图上的标记 (非实时更新模式下使用)
        let polylines = []; // 存储所有轨迹线 (非实时更新模式下使用)
        let infoWindow = null; // 高德地图信息窗体
        let currentSelectedMarker = null; // 存储当前被选中的标记

        // 自定义图标URL
        const redIconUrl = '//webapi.amap.com/theme/v1.3/markers/n/mark_r.png'; // 红色图钉 (用于最新坐标)
        const blueDotContent = '<div class="blue-dot-marker"></div>'; // 蓝色小圆点 (用于历史坐标)
        
        // 初始化ID选择器 (使用 displayIdOptions)
        function initializeIdSelector() {
            idSelector.innerHTML = ''; // 清空现有选项
            if (displayIdOptions.length === 0) {
                const option = document.createElement('option');
                option.value = '';
                option.textContent = '暂无ID数据';
                option.disabled = true;
                idSelector.appendChild(option);
                selectAllIdsButton.disabled = true; // 如果没有ID，禁用全选按钮
            } else {
                displayIdOptions.forEach(idOption => {
                    const option = document.createElement('option');
                    option.value = idOption.original_id; // 值为原始ID
                    option.textContent = idOption.display_name; // 显示为浮标名称（数字ID）
                    option.selected = true; // 默认选中所有ID
                    idSelector.appendChild(option);
                });
                selectAllIdsButton.disabled = false; // 有ID时启用全选按钮
            }
        }

        // 辅助函数：将 YYYY-MM-DD HH:mm:SS 或 YYYY-MM-DDTHH:mm:SS.ms 格式字符串解析为 Date 对象
        // 改进：使用更灵活的正则表达式，兼容T和空格，以及可选的毫秒
        function parseDateTimeString(dtStr) {
            // 兼容 YYYY-MM-DD HH:mm:SS (Flatpickr) 和 YYYY-MM-DDTHH:mm:SS.ms (ISO 8601 from backend)
            const parts = dtStr.match(/(\d{4})-(\d{2})-(\d{2})[T ](\d{2}):(\d{2}):(\d{2})(?:\.\d+)?/);
            if (parts) {
                // new Date(year, monthIndex, day, hours, minutes, seconds, milliseconds)
                // monthIndex 是 0-11，所以需要 -1
                return new Date(
                    parseInt(parts[1]), // year
                    parseInt(parts[2]) - 1, // month (0-11)
                    parseInt(parts[3]), // day
                    parseInt(parts[4]), // hour
                    parseInt(parts[5]), // minute
                    parseInt(parts[6]),  // second
                    0 // milliseconds, we don't need sub-second precision for filtering
                );
            }
            // Fallback for simple Date constructor if regex fails, might still work for some ISO strings
            try {
                const date = new Date(dtStr);
                if (!isNaN(date.getTime())) {
                    return date;
                }
            } catch (e) {
                // console.error("Fallback Date parsing failed:", e);
            }
            console.warn("parseDateTimeString: 无法解析日期时间字符串:", dtStr);
            return null; // 解析失败
        }

        // 辅助函数：将 Date 对象格式化为 YYYY-MM-DD HH:mm:SS
        function formatDateTime(date) {
            if (!date || isNaN(date.getTime())) return null;
            const year = date.getFullYear();
            const month = (date.getMonth() + 1).toString().padStart(2, '0');
            const day = date.getDate().toString().padStart(2, '0');
            const hours = date.getHours().toString().padStart(2, '0');
            const minutes = date.getMinutes().toString().padStart(2, '0');
            const seconds = date.getSeconds().toString().padStart(2, '0');
            return `${year}-${month}-${day} ${hours}:${minutes}:${seconds}`;
        }


        // 辅助函数：判断消息是否匹配日期时间范围
        function messageMatchesDateRange(msg, dateRangeStr) {
            if (!dateRangeStr || dateRangeStr.trim() === '') return true; // 无日期时间范围时，所有消息都匹配

            const receiveTime = msg['接收时间'];
            if (!receiveTime) return false;

            const messageDate = parseDateTimeString(receiveTime);
            if (!messageDate) {
                // 如果消息的接收时间本身都无法解析，那么它肯定不匹配任何有效范围
                return false;
            }

            // Flatpickr 的日期范围字符串通常是 "YYYY-MM-DD HH:mm:SS to YYYY-MM-DD HH:mm:SS"
            // 确保分隔符是 ' to '
            const dates = dateRangeStr.split(' to ');
            const startStr = dates[0];
            const endStr = dates.length > 1 ? dates[1] : null;

            let startDate = startStr ? parseDateTimeString(startStr) : null;
            let endDate = endStr ? parseDateTimeString(endStr) : null;
            
            // 调试信息，确认解析结果
            // console.log(`Filtering: msgTime=${receiveTime}, range=${dateRangeStr}, parsedMsgDate=${messageDate}, parsedStartDate=${startDate}, parsedEndDate=${endDate}`);


            if (startDate && messageDate < startDate) {
                return false;
            }
            // 对于结束日期，我们希望包含当天/当月的所有数据，所以结束时间是23:59:59.999
            // 如果消息时间恰好是结束日期的00:00:00，并且endDate是当天的00:00:00，那也应该包含
            // 这里的endDate已经设置到23:59:59.999，所以直接比较即可
            if (endDate && messageDate > endDate) {
                return false;
            }
            return true;
        }

        // 清空所有地图覆盖物（非实时更新模式）
        function clearAllStaticMapElements() {
            if (map) {
                map.remove(markers);
                map.remove(polylines);
                markers = [];
                polylines = [];
                if (infoWindow && infoWindow.getIsOpen()) infoWindow.close();
                if (currentSelectedMarker) {
                    resetMarkerState(currentSelectedMarker);
                    currentSelectedMarker = null;
                }
                console.log('Cleared all non-realtime map elements.');
            }
        }

        // 清空实时更新模式下的标记
        function clearRealtimeMarkers() {
            if (map) {
                const markersToRemove = Object.values(latestRealtimeMarkers);
                map.remove(markersToRemove);
                latestRealtimeMarkers = {};
                if (infoWindow && infoWindow.getIsOpen()) infoWindow.close();
                if (currentSelectedMarker) { // 清除旧的选中标记状态
                    resetMarkerState(currentSelectedMarker);
                    currentSelectedMarker = null;
                }
                console.log('Cleared all realtime markers.');
            }
        }

        // 核心函数：绘制地图数据（非实时更新模式下调用）
        function renderMapData() {
            console.log('--- renderMapData called (map.html) ---');
            // 如果实时更新正在运行，阻止非实时模式的渲染
            if (realtimeUpdateIntervalId) {
                console.warn("Real-time update is active, cannot render static map data. Please stop real-time update first.");
                noMapDataMessage.textContent = '实时更新正在运行中，无法显示历史数据。请先停止实时更新。';
                noMapDataMessage.className = 'map-status-message warning';
                noMapDataMessage.style.display = 'block';
                return;
            }

            // 清除旧的覆盖物和高亮状态
            clearAllStaticMapElements();
            realtimeStatusMessage.style.display = 'none'; // 隐藏实时更新状态信息

            const selectedIds = Array.from(idSelector.selectedOptions).map(option => option.value); // 获取选中的原始ID
            const mapTimeRangeStr = mapTimeRangeInput.value; // 获取当前 Flatpickr 输入框的值
            const displayMode = document.querySelector('input[name="displayMode"]:checked').value;

            console.log("Rendering map data with filters:", { selectedIds, mapTimeRangeStr, displayMode });


            if (selectedIds.length === 0) {
                noMapDataMessage.textContent = '请选择至少一个ID来显示地图数据。';
                noMapDataMessage.className = 'map-status-message warning';
                noMapDataMessage.style.display = 'block';
                handleDisplayModeChange(); 
                return;
            } else {
                noMapDataMessage.style.display = 'none';
            }

            let allPointsForFitView = []; // 用于地图视野调整的所有有效经纬度点

            let hasDataToShow = false; // 标记是否有任何ID在当前筛选下有数据

            selectedIds.forEach(idNumber => { // idNumber 是原始ID
                const messagesForId = allMessagesGroupedById[idNumber];
                if (!messagesForId || messagesForId.length === 0) return;

                let validLocationsForId = [];

                // 筛选出有有效经纬度的消息，并匹配时间范围
                messagesForId.forEach(msg => {
                    const lat = msg['decimal_latitude'];
                    const lon = msg['decimal_longitude'];
                    
                    if (lat !== null && lon !== null && typeof lat === 'number' && typeof lon === 'number' &&
                        messageMatchesDateRange(msg, mapTimeRangeStr)) {
                        validLocationsForId.push({
                            lnglat: [lon, lat], // 高德地图使用 [longitude, latitude]
                            message: msg, // 完整的格式化消息
                            receiveTime: msg['接收时间']
                        });
                    }
                });

                // 按接收时间降序排序，确保最新点在第一个
                validLocationsForId.sort((a, b) => new Date(b.receiveTime) - new Date(a.receiveTime));


                if (validLocationsForId.length === 0) {
                    console.warn(`ID ${idNumber} (${messagesForId[0].display_id_name}) 在指定条件下没有有效的定位数据。`);
                    return;
                }

                hasDataToShow = true; // 至少有一个ID有数据

                // 根据显示模式绘制
                if (displayMode === 'latest') {
                    const latestLocation = validLocationsForId[0];
                    if (latestLocation) {
                        // 最新位置模式下只显示最新坐标（红色图钉）
                        const marker = createCustomMarker(latestLocation.lnglat, latestLocation.message, 'latest');
                        markers.push(marker);
                        allPointsForFitView.push(new AMap.LngLat(latestLocation.lnglat[0], latestLocation.lnglat[1]));
                    }
                } else if (displayMode === 'trajectory') {
                    // 确保轨迹模式下至少有两个点才能绘制线
                    if (validLocationsForId.length > 1) {
                        // 轨迹需要按时间正序排列
                        validLocationsForId.sort((a, b) => new Date(a.receiveTime) - new Date(b.receiveTime));
                        const path = validLocationsForId.map(loc => loc.lnglat);
                        // 轨迹线固定颜色为灰色
                        const trajectoryColor = '#e77777'; 

                        const polyline = new AMap.Polyline({
                            path: path,
                            strokeColor: trajectoryColor,
                            strokeOpacity: 0.6, // 半透明
                            strokeWeight: 4,
                            strokeStyle: 'solid', // 实线
                            map: map
                        });
                        polylines.push(polyline);
                        // 将所有轨迹点转换为 AMap.LngLat 对象并加入视野调整
                        allPointsForFitView.push(...path.map(p => new AMap.LngLat(p[0], p[1])));
                    }


                    // 轨迹上的每个点也作为一个Marker
                    validLocationsForId.forEach((loc, index) => {
                        let type;
                        // 重新排序后的 validLocationsForId，最后一个点是轨迹的终点
                        if (index === validLocationsForId.length - 1) { 
                            type = 'latest'; // 轨迹的终点（最新点）视为最新坐标 (红色图钉)
                        } else { 
                            type = 'history'; // 其他所有点视为历史坐标 (蓝色小圆点)
                        }
                        const marker = createCustomMarker(loc.lnglat, loc.message, type);
                        markers.push(marker);
                    });
                }
            });

            // 调整地图视野以适应所有点
            if (allPointsForFitView.length > 0) {
                const bounds = new AMap.Bounds();
                allPointsForFitView.forEach(point => {
                    bounds.extend(point);
                });
                map.setFitView(null, false, [50, 50, 50, 50]); // 增加一些边距
                console.log(`Map FitView adjusted to cover ${allPointsForFitView.length} points.`);
            } else {
                noMapDataMessage.textContent = '当前筛选条件下没有找到任何有效的定位数据。';
                noMapDataMessage.className = 'map-status-message warning';
                noMapDataMessage.style.display = 'block';
            }
            
            // 如果最终没有任何数据显示，即使最初有ID选择也显示无数据消息
            if (!hasDataToShow && selectedIds.length > 0) {
                 noMapDataMessage.textContent = '当前筛选条件下，所选ID均无有效的定位数据。';
                 noMapDataMessage.className = 'map-status-message warning';
                 noMapDataMessage.style.display = 'block';
            }


            // 更新图例显示状态
            handleDisplayModeChange();
        }

        /**
         * 创建自定义Marker
         * @param {Array} lnglat - [longitude, latitude]
         * @param {Object} message - 原始消息数据 (包含 display_id_name 和 浮标标识名字)
         * @param {string} type - 'latest', 'history'
         */
        function createCustomMarker(lnglat, message, type) {
            let markerOptions = {
                position: lnglat,
                map: map,
                title: message.display_id_name, // Marker悬停提示显示 display_id_name
                extData: { message: message, type: type } // 存储原始消息和类型
            };

            if (type === 'history') {
                // 历史坐标用蓝色小圆点
                markerOptions.content = blueDotContent;
                markerOptions.offset = new AMap.Pixel(-4, -4); // 确保小圆点中心对齐
            } else { // type === 'latest'
                // 最新坐标用红色图钉
                markerOptions.icon = new AMap.Icon({
                    image: redIconUrl,
                    size: new AMap.Size(25, 34),
                    imageOffset: new AMap.Pixel(0, 0)
                });
                markerOptions.offset = new AMap.Pixel(-12, -34); // 确保图标底部中心对齐
            }

            const marker = new AMap.Marker(markerOptions);

            // 在Marker添加到地图后，存储其DOM引用
            marker.on('added', function() {
                if (type === 'latest') {
                    // 对于红色图钉，我们需要其包含图标的父级元素
                    const markerContent = this.dom.querySelector('.amap-marker-content');
                    if (markerContent) {
                        this.getExtData().markerDOM = markerContent;
                    } else {
                        console.warn("Could not find .amap-marker-content for latest marker.", this);
                        this.getExtData().markerDOM = this.dom; // fallback
                    }
                } else { // 'history'
                    this.getExtData().markerDOM = this.dom; // 蓝色小圆点，它的内容就是其根dom
                }
            });

            // 绑定点击事件
            marker.on('click', (e) => handleMarkerClick(e.target));

            return marker;
        }

        /**
         * 处理标记点击事件
         * @param {AMap.Marker} marker - 被点击的Marker实例
         */
        function handleMarkerClick(marker) {
            const extData = marker.getExtData();
            // 健壮性检查
            if (!extData || !extData.message) {
                console.error("Marker's extended data or message is missing.", marker);
                return;
            }
            const message = extData.message;
            const markerType = extData.type;

            // 如果点击的是当前已选中的标记，则关闭信息窗体并清除高亮
            if (currentSelectedMarker === marker) {
                if (infoWindow && infoWindow.getIsOpen()) infoWindow.close();
                resetMarkerState(currentSelectedMarker); // 恢复上一个选中标记的状态
                currentSelectedMarker = null;
                return;
            }

            // 清除上一个选中标记的高亮
            if (currentSelectedMarker) {
                resetMarkerState(currentSelectedMarker);
            }

            // 设置新选中的标记为高亮状态
            currentSelectedMarker = marker;
            highlightMarker(marker, markerType);

            // 显示详细信息
            showInfoWindow(marker.getPosition(), message);
        }

        /**
         * 处理地图点击事件，用于关闭信息窗体和清除选中状态
         * @param {Object} e - 地图点击事件对象
         */
        function handleMapClick(e) {
            // 判断点击是否发生在Marker或信息窗口内部
            const clickedTarget = e.originalEvent.target;
            const isClickOnMarker = clickedTarget.closest('.amap-marker') !== null;
            const isClickOnInfoWindow = clickedTarget.closest('.amap-info-window') !== null;

            if (isClickOnMarker || isClickOnInfoWindow) {
                // 如果是，则不关闭
                return;
            }

            // 如果点击的是地图空白处，关闭信息窗体并清除选中状态
            if (infoWindow && infoWindow.getIsOpen()) {
                infoWindow.close();
            }
            if (currentSelectedMarker) {
                resetMarkerState(currentSelectedMarker);
                currentSelectedMarker = null;
            }
        }


        /**
         * 高亮显示Marker
         * @param {AMap.Marker} marker
         * @param {string} type - 'latest', 'history'
         */
        function highlightMarker(marker, type) {
            const markerDOM = marker.getExtData().markerDOM;
            if (!markerDOM) {
                console.warn("Marker DOM not found for highlighing.", marker);
                return;
            }

            if (type === 'history') {
                // 蓝色小圆点添加选中样式
                markerDOM.classList.add('selected');
            } else { // 'latest'
                // 红色图钉通过操作其DOM元素来添加高亮类
                markerDOM.classList.add('red-pin-selected');
            }
        }

        /**
         * 恢复Marker到非选中状态
         * @param {AMap.Marker} marker
         */
        function resetMarkerState(marker) {
            const extData = marker.getExtData();
            const type = extData ? extData.type : null;
            const markerDOM = marker.getExtData().markerDOM;

            if (!markerDOM) {
                console.warn("Marker DOM not found for resetting.", marker);
                return;
            }

            if (type === 'history') {
                // 移除蓝色小圆点选中样式
                markerDOM.classList.remove('selected');
            } else { // 'latest'
                // 移除红色图钉的高亮类
                markerDOM.classList.remove('red-pin-selected');
            }
        }

        // 显示信息窗体 (修复：确保数据完整性，并统一处理)
        function showInfoWindow(lnglat, msg) {
            // 确保 lnglat 是有效的 AMap.LngLat 对象
            if (!(lnglat instanceof AMap.LngLat)) {
                console.error("showInfoWindow received invalid LngLat object:", lnglat);
                return;
            }
            
            // 优化显示信息，优先显示有效数据，否则显示 'N/A'
            const messageId = msg['MessageId'] || 'N/A';
            const locateTime = msg['定位时间'] || 'N/A';
            const receiveTime = msg['接收时间'] || 'N/A';
            
            // 增强纬度/经度显示：同时显示格式化后的字符串和解析后的十进制值
            const formattedLatitude = msg['纬度'] || 'N/A';
            const decimalLatitude = (msg['decimal_latitude'] !== null && typeof msg['decimal_latitude'] === 'number') ? msg['decimal_latitude'].toFixed(6) : 'N/A';
            
            const formattedLongitude = msg['经度'] || 'N/A';
            const decimalLongitude = (msg['decimal_longitude'] !== null && typeof msg['decimal_longitude'] === 'number') ? msg['decimal_longitude'].toFixed(6) : 'N/A';

            const altitude = msg['高程'] || 'N/A';
            const customData = msg['自定义数据'] ? (msg['自定义数据'].length > 50 ? msg['自定义数据'].substring(0, 50) + '...' : msg['自定义数据']) : 'N/A';
            const buoyName = msg['浮标标识名字'] || 'N/A'; // 新增浮标标识名字

            let content = `
                <div class="amap-info-window-content">
                    <h4>ID: ${msg['display_id_name'] || 'N/A'} <strong>（已选中）</strong></h4>
                    <div class="info-item"><strong>接收时间:</strong> ${receiveTime}</div>
                    <div class="info-item"><strong>消息ID:</strong> ${messageId}</div>
                    <div class="info-item"><strong>定位时间:</strong> ${locateTime}</div>
                    <div class="info-item"><strong>纬度:</strong> ${formattedLatitude} (${decimalLatitude})</div>
                    <div class="info-item"><strong>经度:</strong> ${formattedLongitude} (${decimalLongitude})</div>
                    <div class="info-item"><strong>高程:</strong> ${altitude}</div>
                    <div class="info-item"><strong>自定义数据:</strong> ${customData}</div>
                    <div class="info-item"><strong>浮标标识名字:</strong> ${buoyName}</div>
                    <p><a href="{{ url_for('history', id_number_param='') }}${encodeURIComponent(msg['IdNumber'] || '')}" target="_blank" class="button secondary" style="padding: 5px 10px; font-size: 0.85em; margin-top: 10px;">查看该ID所有历史消息</a></p>
                </div>
            `;
            infoWindow.setContent(content);
            infoWindow.open(map, lnglat);
        }

        // 创建并添加到地图的图例
        function createMapLegend() {
            const legendDiv = document.createElement('div');
            legendDiv.id = 'map-legend';
            legendDiv.innerHTML = `
                <h4>地图图例</h4>
                <div class="legend-item" id="legend-latest-coordinate">
                    <div class="legend-color-box"><img src="${redIconUrl}" alt="最新坐标"></div>
                    <span>最新坐标</span>
                </div>
                <div class="legend-item" id="legend-history-coordinate">
                    <div class="legend-color-box"><div class="blue-dot-legend"></div></div>
                    <span>历史坐标</span>
                </div>
                <div class="legend-item" id="legend-trajectory-line">
                    <div class="legend-color-box"><div class="polyline-style-legend"></div></div>
                    <span>轨迹线</span>
                </div>
            `;
            mapContainer.appendChild(legendDiv);
            console.log('Map legend created.');
        }

        // 处理显示模式切换时的图例显示逻辑
        function handleDisplayModeChange() {
            const legendLatestCoordinate = document.getElementById('legend-latest-coordinate');
            const legendHistoryCoordinate = document.getElementById('legend-history-coordinate');
            const legendLine = document.getElementById('legend-trajectory-line');

            // 实时更新模式下，只显示“最新坐标”的图例 (其他隐藏)
            if (realtimeUpdateIntervalId) { 
                if (legendLatestCoordinate) legendLatestCoordinate.classList.remove('hidden-legend-item');
                if (legendHistoryCoordinate) legendHistoryCoordinate.classList.add('hidden-legend-item');
                if (legendLine) legendLine.classList.add('hidden-legend-item');
                console.log('Legend display updated for Real-time mode (only latest coordinate shown).');
                return;
            }

            // 非实时更新模式下，根据radio按钮状态显示图例
            const displayMode = document.querySelector('input[name="displayMode"]:checked').value;

            // 最新坐标在两种模式下都可能出现（作为独立最新点或轨迹终点），所以默认不隐藏
            if (legendLatestCoordinate) legendLatestCoordinate.classList.remove('hidden-legend-item'); 

            if (displayMode === 'latest') {
                // 最新位置模式下，隐藏历史坐标和轨迹线
                if (legendHistoryCoordinate) legendHistoryCoordinate.classList.add('hidden-legend-item');
                if (legendLine) legendLine.classList.add('hidden-legend-item');
            } else if (displayMode === 'trajectory') {
                // 轨迹模式下，显示历史坐标和轨迹线
                if (legendHistoryCoordinate) legendHistoryCoordinate.classList.remove('hidden-legend-item');
                if (legendLine) legendLine.classList.remove('hidden-legend-item');
            }
            console.log(`Legend display updated for mode: ${displayMode}`);
        }

        // ===============================================
        // ====== 实时更新功能相关函数 ======
        // ===============================================

        async function updateLatestLocationsOnMap() {
            const selectedIds = Array.from(idSelector.selectedOptions).map(option => option.value); // 获取选中的原始ID

            noMapDataMessage.style.display = 'none'; // 隐藏无数据消息
            realtimeStatusMessage.className = 'map-status-message success'; // 假设成功
            realtimeStatusMessage.style.display = 'block'; // 显示实时更新状态


            if (selectedIds.length === 0) {
                noMapDataMessage.textContent = '实时更新：请至少选择一个ID。';
                noMapDataMessage.className = 'map-status-message warning';
                noMapDataMessage.style.display = 'block';
                realtimeStatusMessage.style.display = 'none';
                clearRealtimeMarkers(); // 确保清空地图
                return;
            }

            console.log("Fetching latest locations for selected IDs:", selectedIds.join(','));
            try {
                const response = await fetch(`/api/latest_locations?id_numbers=${selectedIds.join(',')}`);
                if (!response.ok) {
                    throw new Error(`HTTP error! status: ${response.status}`);
                }
                const rawLatestData = await response.json(); // 获取原始数据
                console.log("Received raw latest data:", rawLatestData);

                // 筛选并验证数据：确保只处理当前选中的ID，且经纬度有效
                const validLatestData = rawLatestData.filter(data => 
                    selectedIds.includes(data.IdNumber) &&
                    data.decimal_latitude !== null && typeof data.decimal_latitude === 'number' &&
                    data.decimal_longitude !== null && typeof data.decimal_longitude === 'number'
                );
                console.log("Filtered and validated latest data for map display:", validLatestData);

                // 清除所有当前实时标记，以避免重复和保持最新状态
                // 仅当选中的marker是实时更新模式下的marker时才重置
                if (currentSelectedMarker && latestRealtimeMarkers[currentSelectedMarker.getExtData().message.IdNumber] === currentSelectedMarker) {
                    resetMarkerState(currentSelectedMarker);
                    currentSelectedMarker = null;
                }
                map.remove(Object.values(latestRealtimeMarkers));
                latestRealtimeMarkers = {}; // 重置

                let allPointsForFitView = []; // 存储所有有效的 AMap.LngLat 对象

                if (validLatestData.length === 0) {
                    // 如果所有选中的ID都没有返回有效数据
                    noMapDataMessage.textContent = '实时更新：所选ID暂无有效的定位数据。';
                    noMapDataMessage.className = 'map-status-message warning';
                    noMapDataMessage.style.display = 'block';
                    realtimeStatusMessage.style.display = 'none'; // 隐藏实时更新状态
                } else {
                    noMapDataMessage.style.display = 'none';
                    realtimeStatusMessage.style.display = 'block'; // 显示实时更新状态
                }

                validLatestData.forEach(data => {
                    const idNum = data.IdNumber;
                    const lat = data.decimal_latitude;
                    const lng = data.decimal_longitude;

                    // 再次确认经纬度有效性，以防万一
                    if (lat !== null && lng !== null) {
                        const newPosition = new AMap.LngLat(lng, lat);
                        
                        const marker = createCustomMarker([lng, lat], data, 'latest'); // createCustomMarker 接受 [lng, lat] 数组
                        latestRealtimeMarkers[idNum] = marker; // 存储新标记
                        map.add(marker); // 添加到地图
                        allPointsForFitView.push(newPosition); // 加入视野调整，这里使用 AMap.LngLat 对象
                    }
                });
                
                // 根据选择的ID数量调整地图视野
                if (allPointsForFitView.length > 0) {
                    if (allPointsForFitView.length === 1) { // 即使选择了多个ID，如果只有一个ID返回有效数据，也只聚焦这个点
                        const singlePoint = allPointsForFitView[0]; // 这是一个 AMap.LngLat 对象
                        map.setCenter(singlePoint);
                        map.setZoom(16); // 设定一个合适的放大级别，例如16
                        console.log(`Map centered and zoomed to single point at zoom 16.`);
                    } else {
                        // 否则，自适应视野以显示所有点（多个ID，或单个ID但意外返回多个点）
                        const bounds = new AMap.Bounds();
                        allPointsForFitView.forEach(point => {
                            bounds.extend(point); 
                        });
                        map.setFitView(null, false, [50, 50, 50, 50]); // 增加一些边距
                        console.log(`Map FitView adjusted to cover ${allPointsForFitView.length} points.`);
                    }
                }

            } catch (error) {
                console.error("Error fetching latest locations:", error);
                noMapDataMessage.textContent = `实时更新失败：${error.message || '网络错误'}`;
                noMapDataMessage.className = 'map-status-message error';
                noMapDataMessage.style.display = 'block';
                realtimeStatusMessage.style.display = 'none';
                stopRealtimeUpdate(); // 停止实时更新
            }
        }

        function startRealtimeUpdate() {
            stopRealtimeUpdate(); // 先清除任何现有定时器

            let interval = parseInt(refreshIntervalInput.value);
            if (isNaN(interval) || interval < 1) {
                interval = defaultRealtimeRefreshInterval;
                refreshIntervalInput.value = defaultRealtimeRefreshInterval;
            }
            currentRefreshIntervalSpan.textContent = interval; // 更新显示的间隔

            console.log(`Starting real-time update with interval: ${interval} seconds`);
            
            clearAllStaticMapElements(); // 清空静态数据
            
            // 禁用常规查询控制项
            setStaticQueryControlsEnabled(false); 
            // 立即执行一次更新
            updateLatestLocationsOnMap(); 
            // 设置定时器
            realtimeUpdateIntervalId = setInterval(updateLatestLocationsOnMap, interval * 1000);

            realtimeStatusMessage.style.display = 'block';
            realtimeControlButton.textContent = '停止实时更新';
            realtimeControlButton.classList.remove('secondary'); 
            realtimeControlButton.classList.add('primary'); // 默认按钮样式
            handleDisplayModeChange(); // 更新图例显示
        }

        function stopRealtimeUpdate() {
            if (realtimeUpdateIntervalId) {
                clearInterval(realtimeUpdateIntervalId);
                realtimeUpdateIntervalId = null;
                console.log("Stopped real-time update.");
                clearRealtimeMarkers(); // 停止实时更新时，清空实时模式下的标记
            }
            setStaticQueryControlsEnabled(true); // 恢复常规查询控制项
            realtimeStatusMessage.style.display = 'none';
            noMapDataMessage.textContent = '实时更新已停止。请选择ID和时间范围，然后点击“显示地图数据”来查看历史数据。';
            noMapDataMessage.className = 'map-status-message'; // 恢复默认样式
            noMapDataMessage.style.display = 'block';
            realtimeControlButton.textContent = '开始实时更新';
            realtimeControlButton.classList.remove('primary');
            realtimeControlButton.classList.add('secondary'); // 可以设置为次要按钮样式
            handleDisplayModeChange(); // 更新图例显示
        }

        /**
         * 启用/禁用常规查询控制项 (ID选择器始终可用)
         * @param {boolean} enable - true为启用，false为禁用
         */
        function setStaticQueryControlsEnabled(enable) {
            // mapTimeRangeInput 的 Flatpickr 实例
            // 直接操作输入框的 disabled 属性即可，Flatpickr 会自动适应
            mapTimeRangeInput.disabled = !enable; 
            
            // 禁用/启用快速选择日期按钮
            todayBtnMap.disabled = !enable;
            lastMonthBtnMap.disabled = !enable;
            allTimeBtnMap.disabled = !enable; // 新增：全部时间按钮

            // 禁用/启用显示模式单选框
            displayModeRadios.forEach(radio => radio.disabled = !enable);
            if (!enable) {
                displayModeLatestRadio.checked = true; // 强制选中最新位置
                // 禁用轨迹选项及对应的标签样式
                displayModeTrajectoryRadio.disabled = true; 
                displayModeTrajectoryRadio.parentNode.style.opacity = '0.5'; 
                displayModeTrajectoryRadio.parentNode.style.cursor = 'not-allowed';
            } else {
                displayModeTrajectoryRadio.disabled = false; 
                displayModeTrajectoryRadio.parentNode.style.opacity = '1'; 
                displayModeTrajectoryRadio.parentNode.style.cursor = 'pointer';
            }
            
            // 禁用/启用显示地图数据按钮
            displayMapDataButton.disabled = !enable;
            
            console.log(`Static query controls ${enable ? 'enabled' : 'disabled'}.`);
        }

        // ===============================================
        // ====== 页面初始化逻辑 ======
        // ===============================================
        document.addEventListener('DOMContentLoaded', () => {
            initializeIdSelector();
            createMapLegend(); // 在DOM加载完成后创建图例
            
            // 初始化地图，但不立即加载数据
            map = new AMap.Map('container', {
                zoom: 11,
                center: [116.397428, 39.90923], // 初始中心点：北京
                viewMode: '3D'
            });
            map.addControl(new AMap.ToolBar());
            map.addControl(new AMap.Scale());
            map.addControl(new AMap.ControlBar()); // 3D视图控件

            infoWindow = new AMap.InfoWindow({offset: new AMap.Pixel(0, -30)});
            map.on('click', handleMapClick);

            // 初始化 Flatpickr for mapTimeRangeInput
            let fpInstance = flatpickr(mapTimeRangeInput, {
                mode: "range",
                dateFormat: "Y-m-d H:i:S", // Flatpickr 输出格式
                enableTime: true,
                time_24hr: true,
                locale: "zh",
                // 默认选择全部时间，这样在页面加载后，如果用户没有选择，点击显示地图数据按钮，会显示所有历史数据
                // 确保 Flatpickr 的 defaultDate 输出的格式能被 parseDateTimeString 准确解析
                defaultDate: [formatDateTime(new Date('1970-01-01T00:00:00Z')), formatDateTime(new Date(new Date().getFullYear(), new Date().getMonth(), new Date().getDate(), 23, 59, 59, 999))],
                onChange: function(selectedDates, dateStr, instance) {
                    // 当时间范围改变时，如果实时更新正在运行，需要停止它
                    if (realtimeUpdateIntervalId) {
                        stopRealtimeUpdate();
                    }
                    // 此处不再自动调用 renderMapData，而是由快速按钮或“显示地图数据”按钮显式触发
                    // console.log("Flatpickr onChange triggered. Selected dates:", selectedDates, "Date string:", dateStr);
                }
            });


            // ====== 绑定事件监听器 ======
            // 非实时模式的“显示地图数据”按钮事件
            displayMapDataButton.addEventListener('click', renderMapData);

            // 绑定显示模式切换事件 (非实时模式下)
            displayModeRadios.forEach(radio => {
                radio.addEventListener('change', handleDisplayModeChange);
            });

            // 全选按钮事件
            selectAllIdsButton.addEventListener('click', () => {
                Array.from(idSelector.options).forEach(option => {
                    if (!option.disabled) { 
                        option.selected = true;
                    }
                });
                console.log('All IDs selected.');
                if (realtimeUpdateIntervalId) { // 如果实时更新正在运行，且用户全选ID，触发一次更新
                    updateLatestLocationsOnMap();
                }
            });
            
            // 实时控制按钮事件（开始/停止实时更新）
            realtimeControlButton.addEventListener('click', function() {
                if (realtimeUpdateIntervalId) { // 如果正在运行，则停止
                    stopRealtimeUpdate();
                } else { // 如果没有运行，则开始
                    startRealtimeUpdate();
                }
            });

            // 刷新间隔输入框事件
            refreshIntervalInput.addEventListener('change', function() {
                if (realtimeUpdateIntervalId) { // 如果实时更新正在运行，调整间隔后重新启动定时器
                    startRealtimeUpdate(); 
                }
            });
            refreshIntervalInput.value = parseInt(refreshIntervalInput.value) || defaultRealtimeRefreshInterval;
            refreshIntervalInput.min = "1"; // 确保最小值为1秒

            // 新增：今天按钮事件
            todayBtnMap.addEventListener('click', () => {
                const todayStart = new Date();
                todayStart.setHours(0, 0, 0, 0); 
                const todayEnd = new Date();
                todayEnd.setHours(23, 59, 59, 999); 
                fpInstance.setDate([todayStart, todayEnd], true); // true 触发 onChange (停止实时更新)
                console.log('Set date range to: Today');
                // 在非实时模式下，点击后立即渲染数据
                if (!realtimeUpdateIntervalId) { 
                    renderMapData();
                }
            });

            // 新增：最近一月按钮事件
            lastMonthBtnMap.addEventListener('click', () => {
                const now = new Date();
                const oneMonthAgo = new Date();
                oneMonthAgo.setMonth(now.getMonth() - 1); 
                oneMonthAgo.setHours(0, 0, 0, 0); 
                const endOfToday = new Date();
                endOfToday.setHours(23, 59, 59, 999); 
                fpInstance.setDate([oneMonthAgo, endOfToday], true); // true 触发 onChange (停止实时更新)
                console.log('Set date range to: Last Month');
                // 在非实时模式下，点击后立即渲染数据
                if (!realtimeUpdateIntervalId) { 
                    renderMapData();
                }
            });

            // 新增：全部时间按钮事件
            allTimeBtnMap.addEventListener('click', () => {
                // Flatpickr 默认的 "Y-m-d H:i:S" 格式，需要确保传入的日期是可被格式化的
                // 对于最早日期，使用一个明确的 Date 对象
                const earliest = new Date('1970-01-01T00:00:00Z'); 
                const now = new Date();
                now.setHours(23, 59, 59, 999); // 到今天结束
                fpInstance.setDate([earliest, now], true); // true 触发 onChange (停止实时更新)
                console.log('Set date range to: All Time');
                // 在非实时模式下，点击后立即渲染数据
                if (!realtimeUpdateIntervalId) { 
                    renderMapData();
                }
            });


            // 页面加载后的默认行为：
            if (displayIdOptions.length > 0) { // 判断是否有ID数据
                // 1. initializeIdSelector 已经默认选中所有ID
                // 2. 确保“最新位置”被选中 
                displayModeLatestRadio.checked = true;
                // 3. 默认启动实时更新
                startRealtimeUpdate(); 
                console.log('Default: Starting real-time update for all IDs.');
            } else {
                noMapDataMessage.textContent = '暂无ID数据可显示，请稍后重试。';
                noMapDataMessage.className = 'map-status-message warning';
                noMapDataMessage.style.display = 'block';
                
                handleDisplayModeChange(); // 初始化图例状态
                // 如果没有ID，所有操作都应禁用
                setStaticQueryControlsEnabled(false); 
                selectAllIdsButton.disabled = true;
                refreshIntervalInput.disabled = true;
                realtimeControlButton.disabled = true;
                realtimeControlButton.textContent = '无ID数据';
            }

            // 当ID选择器选择发生变化时，如果实时更新正在运行，重新加载数据
            idSelector.addEventListener('change', () => {
                if (realtimeUpdateIntervalId) {
                    console.log('ID selection changed during real-time update, refreshing map data...');
                    updateLatestLocationsOnMap();
                }
            });
        });

    </script>
{% endblock %}
